﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MyGrid.Core.HexTypeA.Extensions
{
    public static class MGVector2IExtensions
    {
        public static MGVector2I GetNear(this MGVector2I position, HexTypeADirection direction)
        {
            var offset = GetDirectionOffset(position.Y, direction);
            return new MGVector2I(position.X + offset.X, position.Y + offset.Y);
        }


        ///<summary>获得指定方向指定距离的目标格子。</summary>
        public static MGVector2I GetNear(this MGVector2I position, HexTypeADirection direction, int distance)
        {
            if (distance == 0) return position;
            var tureDirection = direction;
            var tureDistance = distance;
            if (distance < 0)
            {
                tureDirection = direction.Reverse();
                tureDistance = Math.Abs(distance);
            }

            var unitOffset1 = GetDirectionOffset(position.Y, direction);
            var unitOffset2 = GetDirectionOffset(position.Y + 1, direction);

            if (distance % 2 == 0)
            {
                var offsetX = (unitOffset1.X + unitOffset2.X) * distance / 2;
                var offsetY = (unitOffset1.Y + unitOffset2.Y) * distance / 2;
                return new MGVector2I(position.X + offsetX, position.Y + offsetY);
            }
            else
            {
                var offsetX = unitOffset1.X * (distance + 1) / 2 + unitOffset2.X * distance / 2;
                var offsetY = unitOffset1.Y * (distance + 1) / 2 + unitOffset2.Y * distance / 2;
                return new MGVector2I(position.X + offsetX, position.Y + offsetY);
            }


        }

        private static MGVector2I GetDirectionOffset(int yId, HexTypeADirection direction)
        {
            if (yId % 2 == 0)
            {
                return direction switch
                {
                    HexTypeADirection.Left => new MGVector2I(-1, 0),
                    HexTypeADirection.Right => new MGVector2I(+1, 0),
                    HexTypeADirection.LeftUp => new MGVector2I(0, -1),
                    HexTypeADirection.RightUp => new MGVector2I(+1, -1),
                    HexTypeADirection.LeftDown => new MGVector2I(0, +1),
                    HexTypeADirection.RightDown => new MGVector2I(+1, +1),
                };
            }
            else
            {
                return direction switch
                {
                    HexTypeADirection.Left => new MGVector2I(-1, 0),
                    HexTypeADirection.Right => new MGVector2I(+1, 0),
                    HexTypeADirection.LeftUp => new MGVector2I(-1, -1),
                    HexTypeADirection.RightUp => new MGVector2I(0, -1),
                    HexTypeADirection.LeftDown => new MGVector2I(-1, +1),
                    HexTypeADirection.RightDown => new MGVector2I(0, +1),
                };
            }
        }

        public static MGVector2I[] GetRing(this MGVector2I position, int distance)
        {
            if (distance == 0) return [position];
            distance = Math.Abs(distance);

            var list = new List<MGVector2I>();
            //list.Add(position);

            GetRingCore(ref list, ref position, distance);

            return list.ToArray();
        }

        private static void GetRingCore(ref List<MGVector2I> list, ref MGVector2I position, int distance)
        {
            var startPoint = position.GetNear(HexTypeADirection.LeftUp, distance);
            var seekDirection = HexTypeADirection.Right;

            if(distance == 0)
            {
                list.Add(position);
                return;
            }

            for (int i = 0; i < HexTypeADirectionExtension.DirectionCount; i++)
            {
                for (int j = 0; j < distance; j++)
                {
                    var point = startPoint.GetNear(seekDirection, j);
                    list.Add(point);
                }

                startPoint = startPoint.GetNear(seekDirection, distance);
                seekDirection = seekDirection.GetNextClockDirection();
            }
        }

        public static MGVector2I[] GetArea(this MGVector2I position, int distance)
        {
            if (distance == 0) return [position];
            distance = Math.Abs(distance);

            var list = new List<MGVector2I>();

            for (int i = 0; i <= distance; i++)
            {
                GetRingCore(ref list, ref position, i);
            }

            return list.ToArray();
        }

      
    }
}
